#include "multichartwindow.h"
#include <QVBoxLayout>
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>

MultiChartWindow::MultiChartWindow(QWidget *parent) :
    QMainWindow(parent),
    maxPoints(2000),
    dragChartIndex(-1),
    dragPointIndex(-1),
    isDragging(false),
    firstDataReceived(false)
{
    setWindowTitle("多传感器状态监测系统");
    setMinimumSize(1200, 800);
    resize(1600, 1200); // 增大窗口默认大小
    
    initCharts();
}

MultiChartWindow::~MultiChartWindow()
{
    // 释放所有图表相关资源
    for (int i = 0; i < 6; ++i) {
        delete series[i];
        delete axesX[i];
        delete axesY[i];
        delete charts[i];
        // chartViews由布局管理，不需要手动删除
    }
}

void MultiChartWindow::initCharts()
{
    // 创建中央部件
    centralWidget = new QWidget(this);
    setCentralWidget(centralWidget);
    
    // 创建主垂直布局
    QVBoxLayout *outerLayout = new QVBoxLayout(centralWidget);
    
    // 创建网格布局来放置图表
    mainLayout = new QGridLayout();
    mainLayout->setSpacing(10);
    mainLayout->setContentsMargins(10, 10, 10, 10);
    
    // 初始化六个图表
    for (int i = 0; i < 6; ++i) {
        // 创建图表
        charts[i] = new QChart();
        series[i] = new QLineSeries();
        
        charts[i]->addSeries(series[i]);
        charts[i]->setTitle(channelTitles[i]);
        charts[i]->setAnimationOptions(QChart::SeriesAnimations);
        charts[i]->legend()->hide();
        
        // 设置X轴（时间轴） - 改为使用QDateTimeAxis
        axesX[i] = new QDateTimeAxis();
        axesX[i]->setTitleText("时间");
        axesX[i]->setFormat("hh:mm:ss.zzz"); // 设置时间格式，包括毫秒
        axesX[i]->setTickCount(6); // 设置刻度数量
        QDateTime now = QDateTime::currentDateTime();
        axesX[i]->setRange(now, now.addMSecs(static_cast<qint64>(maxPoints))); // 初始范围设置为当前时间到当前时间+maxPoints毫秒
        charts[i]->addAxis(axesX[i], Qt::AlignBottom);
        series[i]->attachAxis(axesX[i]);
        
        // 设置Y轴（数据轴）
        axesY[i] = new QValueAxis();
        
        // 根据通道类型设置不同的Y轴标题、范围和精度
        switch (i) {
        case 0:
        case 1:
        case 2: // 加速度通道
            axesY[i]->setTitleText("加速度 (m/s²)");
            axesY[i]->setRange(0, 30);
            axesY[i]->setLabelFormat("%.1f"); // 设置Y轴精度为1位小数
            break;
        case 3: // 声强通道
            axesY[i]->setTitleText("声强");
            axesY[i]->setRange(0, 30);
            axesY[i]->setLabelFormat("%.0f"); // 设置Y轴精度为整数
            break;
        case 4: // 温度通道
            axesY[i]->setTitleText("温度 (°C)");
            axesY[i]->setRange(0, 30);
            axesY[i]->setLabelFormat("%.1f"); // 设置Y轴精度为1位小数
            break;
        case 5: // 电压通道
            axesY[i]->setTitleText("电压 (V)");
            axesY[i]->setRange(0, 30);
            axesY[i]->setLabelFormat("%.2f"); // 设置Y轴精度为2位小数
            break;
        }
        
        charts[i]->addAxis(axesY[i], Qt::AlignLeft);
        series[i]->attachAxis(axesY[i]);
        
        // 创建图表视图
        chartViews[i] = new QChartView(charts[i]);
        chartViews[i]->setRenderHint(QPainter::Antialiasing);
        chartViews[i]->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        
        // 允许图表交互
        chartViews[i]->setRubberBand(QChartView::RectangleRubberBand);
        chartViews[i]->setInteractive(true);
        charts[i]->setAcceptHoverEvents(true);
        chartViews[i]->setDragMode(QGraphicsView::ScrollHandDrag);
        chartViews[i]->setMouseTracking(true);
        chartViews[i]->installEventFilter(this);
        
        // 将图表视图添加到网格布局中（3行2列）
        int row = i / 2;
        int col = i % 2;
        mainLayout->addWidget(chartViews[i], row, col);
    }
    
    // 将网格布局添加到主垂直布局
    outerLayout->addLayout(mainLayout);
    
    // 初始化控制按钮和采样参数调节控件
    initControls(outerLayout);
}

void MultiChartWindow::initControls(QVBoxLayout *outerLayout)
{
    // 创建按钮布局
    QHBoxLayout *buttonLayout = new QHBoxLayout();
    buttonLayout->setSpacing(10);
    
    // 创建清除按钮
    clearButton = new QPushButton("清除所有曲线");
    clearButton->setFixedHeight(40);
    buttonLayout->addWidget(clearButton);
    
    // 创建一键自动锁定最优视图按钮
    autoFitButton = new QPushButton("一键自动锁定最优视图");
    autoFitButton->setFixedHeight(40);
    buttonLayout->addWidget(autoFitButton);
    
    // 添加按钮布局到主布局
    outerLayout->addLayout(buttonLayout);
    
    // 创建采样参数调节布局
    QHBoxLayout *sampleControlsLayout = new QHBoxLayout();
    sampleControlsLayout->setSpacing(20);
    
    // 采样点数量调节
    sampleControlsLayout->addWidget(new QLabel("采样点数量:"));
    sampleSizeEdit = new QLineEdit(QString::number(maxPoints));
    sampleSizeEdit->setMaximumWidth(80);
    sampleControlsLayout->addWidget(sampleSizeEdit);
    sampleSizeLabel = new QLabel(QString::number(maxPoints));
    sampleControlsLayout->addWidget(sampleSizeLabel);
    sampleSizeRangeLabel = new QLabel("(范围: 50-500000)");
    sampleSizeRangeLabel->setStyleSheet("color: gray; font-size: 10px;");
    sampleControlsLayout->addWidget(sampleSizeRangeLabel);

    // 采样时间调节
    sampleControlsLayout->addWidget(new QLabel("采样时间范围:"));
    sampleTimeEdit = new QLineEdit("5");
    sampleTimeEdit->setMaximumWidth(80);
    sampleControlsLayout->addWidget(sampleTimeEdit);
    sampleTimeLabel = new QLabel("5 ms");
    sampleControlsLayout->addWidget(sampleTimeLabel);
    sampleTimeRangeLabel = new QLabel("(范围: 1-10000 ms)");
    sampleTimeRangeLabel->setStyleSheet("color: gray; font-size: 10px;");
    sampleControlsLayout->addWidget(sampleTimeRangeLabel);
    
    // 添加采样参数调节布局到主布局
    outerLayout->addLayout(sampleControlsLayout);
    
    // 连接信号和槽
    connect(clearButton, &QPushButton::clicked, this, &MultiChartWindow::clearAllData);
    connect(autoFitButton, &QPushButton::clicked, this, &MultiChartWindow::autoFitAllViews);
    connect(sampleSizeEdit, &QLineEdit::editingFinished, this, [=]() {
        bool ok;
        qint64 value = sampleSizeEdit->text().toLongLong(&ok);
        if (ok && value >= 50) { // 验证输入在有效范围内（下限为50，上限理论上无限制）
            sampleSizeLabel->setText(QString::number(value));
            setMaxPoints(value);
            emit sampleSizeChanged(value);
        } else {
            // 输入无效，恢复之前的值
            sampleSizeEdit->setText(QString::number(maxPoints));
            QMessageBox::warning(this, "输入错误", "采样点数量必须大于等于50");
        }
    });
    connect(sampleTimeEdit, &QLineEdit::editingFinished, this, [=]() {
        bool ok;
        int value = sampleTimeEdit->text().toInt(&ok);
        if (ok && value >= 1 && value <= 10000) { // 验证输入在有效范围内
            sampleTimeLabel->setText(QString::number(value) + " ms");
            setSampleTime(value);
            emit sampleTimeChanged(value);
        } else {
            // 输入无效，恢复之前的值
            sampleTimeEdit->setText("5");
            QMessageBox::warning(this, "输入错误", "采样时间必须在1-10000 ms之间");
        }
    });
}

void MultiChartWindow::addDataPoint(int channelIndex, double x, double y)
{
    if (channelIndex < 0 || channelIndex >= 6) {
        return; // 通道索引无效
    }
    
    // 处理第一个数据点，记录当前时间
    if (!firstDataReceived) {
        firstDataTime = QDateTime::currentDateTime();
        firstDataReceived = true;
    }
    
    // 将数据计数器x转换为实际时间戳
    // 假设x是一个递增的计数器，我们将其映射到从firstDataTime开始的时间轴上
    // 这里简单地假设每个数据点之间间隔1毫秒，可以根据实际需求调整
    QDateTime dataTime = firstDataTime.addMSecs(static_cast<qint64>(x));
    
    // 将QDateTime转换为QPointF可接受的毫秒时间戳（从 epoch 开始的毫秒数）
    qint64 timestamp = dataTime.toMSecsSinceEpoch();
    
    // 添加数据点
    series[channelIndex]->append(timestamp, y);
    
    // 优化数据点管理和X轴范围控制
    if (series[channelIndex]->count() > maxPoints) {
        // 保留最新的maxPoints个数据点
        QList<QPointF> points = series[channelIndex]->points();
        points.removeFirst();
        series[channelIndex]->replace(points);
    }
    
    // 始终更新X轴范围，显示最新的maxPoints个数据点
    if (series[channelIndex]->count() > 0) {
        qint64 currentMaxTimestamp = static_cast<qint64>(series[channelIndex]->points().last().x());
        QDateTime currentMaxTime = QDateTime::fromMSecsSinceEpoch(currentMaxTimestamp);
        
        // 对于真正的滚动窗口效果，当有足够多的数据点时，显示最新的maxPoints个
        if (series[channelIndex]->count() >= maxPoints) {
            // 计算X轴的最小值，确保显示最新的maxPoints个数据点
            qint64 currentMinTimestamp = static_cast<qint64>(series[channelIndex]->points().first().x());
            QDateTime currentMinTime = QDateTime::fromMSecsSinceEpoch(currentMinTimestamp);
            axesX[channelIndex]->setRange(currentMinTime, currentMaxTime);
        } else {
            // 数据点较少时，从第一个数据点的时间开始显示
            axesX[channelIndex]->setRange(firstDataTime, currentMaxTime);
        }
    } else {
        // 没有数据时，保持初始范围
        QDateTime now = QDateTime::currentDateTime();
        axesX[channelIndex]->setRange(now, now.addMSecs(static_cast<qint64>(maxPoints)));
    }
    
    // 不再自动调整Y轴范围，允许用户自由拖动
    // 只有在首次添加数据时调整Y轴范围
    if (series[channelIndex]->count() == 1) {
        // 根据通道类型设置不同的Y轴初始范围，不再强制最小值为0
        // 但仍然保持非负值
        double yMin = qMax(0.0, y - 5); // 为第一个点提供一些上下空间，但保持非负值
        double yMax = y + 5;
        axesY[channelIndex]->setRange(yMin, yMax);
    }
}

void MultiChartWindow::clearAllData()
{
    // 显示确认对话框
    QMessageBox::StandardButton reply;
    reply = QMessageBox::question(this, "确认清除数据", "确定要清除所有通道的数据吗？",
                                 QMessageBox::Yes | QMessageBox::No);
    
    if (reply == QMessageBox::Yes) {
        // 清除所有图表的数据
        for (int i = 0; i < 6; ++i) {
            series[i]->clear();
            // 清除数据后，重新设置时间轴范围为当前时间到当前时间+maxPoints毫秒
            QDateTime now = QDateTime::currentDateTime();
            axesX[i]->setRange(now, now.addMSecs(static_cast<qint64>(maxPoints)));
            // 保持Y轴范围不变，让用户可以继续使用之前的拖动位置
        }
        
        // 重置数据接收状态
        firstDataReceived = false;
        
        // 发送信号通知主窗口重置数据计数器
        emit resetDataCounter();
    }
}

bool MultiChartWindow::eventFilter(QObject *obj, QEvent *e)
{
    // 查找哪个图表视图触发了事件
    int chartIndex = -1;
    for (int i = 0; i < 6; ++i) {
        if (obj == chartViews[i]) {
            chartIndex = i;
            break;
        }
    }
    
    // 忽略非chartView对象的事件
    if (chartIndex == -1)
        return false;
    
    // 只有在处理特定事件时才返回true，否则让事件继续传递
    if (e->type() == QEvent::MouseButtonPress) {
        QMouseEvent *event = static_cast<QMouseEvent *>(e);
        if (event->button() == Qt::LeftButton) {
            // 转换鼠标位置到图表坐标系
            QPointF scenePoint = chartViews[chartIndex]->mapToScene(event->pos());
            QPointF chartPoint = charts[chartIndex]->mapFromScene(scenePoint);
            
            // 查找最近的数据点
            int closestPoint = -1;
            double minDistance = 10.0; // 设置一个合适的阈值
            QList<QPointF> points = series[chartIndex]->points();
            
            for (int i = 0; i < points.size(); ++i) {
                double distance = qSqrt(qPow(points[i].x() - chartPoint.x(), 2) + 
                                      qPow(points[i].y() - chartPoint.y(), 2));
                if (distance < minDistance) {
                    minDistance = distance;
                    closestPoint = i;
                }
            }
            
            // 如果找到足够近的数据点，开始拖动
            if (closestPoint != -1) {
                dragChartIndex = chartIndex;
                dragPointIndex = closestPoint;
                isDragging = true;
                return true; // 处理了事件，阻止默认行为
            }
            // 未找到数据点，让事件继续传递，以便ScrollHandDrag功能正常工作
            return false;
        }
    } else if (e->type() == QEvent::MouseMove && isDragging && dragChartIndex == chartIndex) {
        QMouseEvent *event = static_cast<QMouseEvent *>(e);
        
        // 转换鼠标位置到图表坐标系
        QPointF scenePoint = chartViews[chartIndex]->mapToScene(event->pos());
        QPointF chartPoint = charts[chartIndex]->mapFromScene(scenePoint);
        
        // 更新拖动的数据点
        if (dragPointIndex >= 0 && dragPointIndex < series[chartIndex]->points().size()) {
            QList<QPointF> points = series[chartIndex]->points();
            points[dragPointIndex] = chartPoint;
            series[chartIndex]->replace(points);
        }
        return true; // 正在拖动数据点时处理事件
    } else if (e->type() == QEvent::MouseButtonRelease) {
        isDragging = false;
        dragChartIndex = -1;
        dragPointIndex = -1;
        return true; // 处理了事件
    }
    
    // 对于其他所有事件，让它们继续传递给默认处理程序
    return false;
}


void MultiChartWindow::setMaxPoints(qint64 newMaxPoints)
{
    maxPoints = newMaxPoints;
    
    // 更新所有图表的X轴范围，保持当前显示逻辑
    for (int i = 0; i < 6; ++i) {
        if (series[i]->count() > 0) {
            // 获取当前最大的timestamp
            qint64 currentMaxTimestamp = static_cast<qint64>(series[i]->points().last().x());
            QDateTime currentMaxTime = QDateTime::fromMSecsSinceEpoch(currentMaxTimestamp);
            
            // 对于足够多的数据点，调整为滚动窗口效果
            if (series[i]->count() >= maxPoints) {
                // 使用最早的数据点时间作为最小值
                qint64 currentMinTimestamp = static_cast<qint64>(series[i]->points().first().x());
                QDateTime currentMinTime = QDateTime::fromMSecsSinceEpoch(currentMinTimestamp);
                axesX[i]->setRange(currentMinTime, currentMaxTime);
            } else {
                // 数据点较少时，从第一个数据点的时间开始显示
                if (firstDataReceived) {
                    axesX[i]->setRange(firstDataTime, currentMaxTime);
                } else {
                    // 如果还没有收到数据，使用当前时间范围
                    QDateTime now = QDateTime::currentDateTime();
                    axesX[i]->setRange(now, now.addMSecs(static_cast<qint64>(maxPoints)));
                }
            }
        } else {
            // 没有数据时，设置时间轴范围为当前时间到当前时间+maxPoints毫秒
            QDateTime now = QDateTime::currentDateTime();
            axesX[i]->setRange(now, now.addMSecs(static_cast<qint64>(maxPoints)));
        } 
    }
}

void MultiChartWindow::updateTimeAxisWithoutData()
{
    // 获取当前时间
    QDateTime currentDateTime = QDateTime::currentDateTime();
    qreal xValue = currentDateTime.toMSecsSinceEpoch();
    
    // 如果是第一个数据点，记录开始时间
    if (!firstDataReceived) {
        firstDataTime = currentDateTime;
        firstDataReceived = true;
    }
    
    // 遍历所有通道，添加0值数据点
    for (int i = 0; i < 6; ++i) {
        if (series[i] && series[i]->count() > 0) {
            series[i]->append(xValue, 0); // 添加0值数据点
            
            // 保持数据点数量不超过maxPoints
            if (series[i]->count() > maxPoints) {
                series[i]->remove(0);
            }
            
            // 更新X轴范围，让时间轴继续滚动
            if (axesX[i]) {
                QDateTime startDateTime = currentDateTime.addMSecs(-maxPoints); // 显示最近maxPoints毫秒的数据
                axesX[i]->setRange(startDateTime, currentDateTime);
            }
        }
    }
}

void MultiChartWindow::setSampleTime(int sampleTime)
{
    // 实现采样时间的设置逻辑
    sampleTimeLabel->setText(QString::number(sampleTime) + " ms");
}

void MultiChartWindow::updateControlsSilently(qint64 newMaxPoints, int newSampleTime)
{
    // 暂时断开信号连接，防止循环触发
    disconnect(sampleSizeEdit, &QLineEdit::editingFinished, nullptr, nullptr);
    disconnect(sampleTimeEdit, &QLineEdit::editingFinished, nullptr, nullptr);
    
    // 更新控件值
    sampleSizeEdit->setText(QString::number(newMaxPoints));
    sampleSizeLabel->setText(QString::number(newMaxPoints));
    sampleTimeEdit->setText(QString::number(newSampleTime));
    sampleTimeLabel->setText(QString::number(newSampleTime) + " ms");
    
    // 更新内部状态
    maxPoints = newMaxPoints;
    setSampleTime(newSampleTime);
    
    // 重新连接信号
    connect(sampleSizeEdit, &QLineEdit::editingFinished, this, [=]() {
        bool ok;
        qint64 value = sampleSizeEdit->text().toLongLong(&ok);
        if (ok && value >= 50 && value <= 500000) { // 验证输入在有效范围内
            sampleSizeLabel->setText(QString::number(value));
            setMaxPoints(value);
            emit sampleSizeChanged(value);
        } else {
            // 输入无效，恢复之前的值
            sampleSizeEdit->setText(QString::number(maxPoints));
            QMessageBox::warning(this, "输入错误", "采样点数量必须在50-500000之间");
        }
    });
    connect(sampleTimeEdit, &QLineEdit::editingFinished, this, [=]() {
        bool ok;
        int value = sampleTimeEdit->text().toInt(&ok);
        if (ok && value >= 1 && value <= 10000) { // 验证输入在有效范围内
            sampleTimeLabel->setText(QString::number(value) + " ms");
            setSampleTime(value);
            emit sampleTimeChanged(value);
        } else {
            // 输入无效，恢复之前的值
            sampleTimeEdit->setText("1000");
            QMessageBox::warning(this, "输入错误", "采样时间必须在1-10000 ms之间");
        }
    });
}

void MultiChartWindow::autoFitAllViews()
{
    // 遍历所有六个通道，自动调整每个图表的显示范围
    for (int i = 0; i < 6; ++i) {
        if (series[i]->count() > 0) {
            QList<QPointF> points = series[i]->points();
            
            // 计算数据点的Y值的极值
            double minY = points.first().y();
            double maxY = points.first().y();
            
            for (int j = 1; j < points.size(); ++j) {
                minY = qMin(minY, points[j].y());
                maxY = qMax(maxY, points[j].y());
            }
            
            // 添加适当的边距，确保数据完全显示且美观
            double yMargin = (maxY - minY) * 0.1;
            if (maxY == minY) {
                // 特殊情况：所有点的Y值相同，设置一个合理的范围
                yMargin = 1.0;
            }
            
            // 设置X轴范围
            qint64 currentMaxTimestamp = static_cast<qint64>(points.last().x());
            QDateTime currentMaxTime = QDateTime::fromMSecsSinceEpoch(currentMaxTimestamp);
            
            // 对于足够多的数据点，显示最新的maxPoints个
            if (points.size() >= maxPoints) {
                qint64 currentMinTimestamp = static_cast<qint64>(points.first().x());
                QDateTime currentMinTime = QDateTime::fromMSecsSinceEpoch(currentMinTimestamp);
                axesX[i]->setRange(currentMinTime, currentMaxTime);
            } else {
                // 数据点较少时，从第一个数据点的时间开始显示
                if (firstDataReceived) {
                    axesX[i]->setRange(firstDataTime, currentMaxTime);
                } else {
                    // 如果还没有收到数据，使用当前时间范围
                    QDateTime now = QDateTime::currentDateTime();
                    axesX[i]->setRange(now, now.addMSecs(static_cast<qint64>(maxPoints)));
                }
            }
            
            // 设置Y轴范围，不再强制最小值为0，但保持非负值
            double adjustedMinY = qMax(0.0, minY - yMargin);
            axesY[i]->setRange(adjustedMinY, maxY + yMargin);
        }
    }
}
